package com.zyk.scaffold.oauth.controller.captcha;

import com.zyk.scaffold.common.utils.AssertUtil;
import com.zyk.scaffold.common.utils.MD5Util;
import com.zyk.scaffold.oauth.captcha.VerificationCodeUtil;
import com.zyk.scaffold.oauth.component.CaptchaComponent;
import com.zyk.scaffold.oauth.enums.OauthErrorCodeEnum;
import com.zyk.scaffold.core.domain.Result;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.RandomStringUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;

import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.security.NoSuchAlgorithmException;
import java.util.UUID;

@Api(tags = "验证-API")
@Slf4j
@RestController
@RequestMapping("/captcha")
public class CaptchaController {

    private static final int SMS_CAPTCHA_CACHE_TTL = 60000;
    private static final String SMS_CAPTCHA_CACHE_KEY = "smsCaptcha:";
    private static final int CAPTCHA_CACHE_TTL = 60000;
    public static final String CAPTCHA_CACHE_KEY = "captcha:";

    @Autowired
    private CaptchaComponent captchaComponent;

    @Autowired
    private RedisTemplate redisTemplate;

    @ResponseBody
    @GetMapping("/sms")
    @ApiOperation(value = "短信")
    public Result<CaptchaResponse> captchaSms(@ModelAttribute @Validated CaptchaSmsRequest captchaSmsRequest) {
        String captcha = captchaComponent.getCaptcha(captchaSmsRequest.getGraphId());
        if (StringUtils.equalsIgnoreCase(captchaSmsRequest.getCaptcha(), captcha)) {
            String uuid = UUID.randomUUID().toString();
            String smsCaptcha = RandomStringUtils.randomNumeric(6);
            redisTemplate.opsForValue().set(SMS_CAPTCHA_CACHE_KEY + uuid, captchaSmsRequest.getPhone() + "_" + smsCaptcha, SMS_CAPTCHA_CACHE_TTL);
            log.info("smsCaptcha=" + smsCaptcha);
            // TODO send sms smsCaptcha
            CaptchaResponse captchaResponse = new CaptchaResponse();
            captchaResponse.setTtl(SMS_CAPTCHA_CACHE_TTL);
            captchaResponse.setGraphId(uuid);
            captchaComponent.removeCaptcha(captchaSmsRequest.getGraphId());
            return Result.ok(captchaResponse);
        }
        return Result.error(OauthErrorCodeEnum.CAPTCHA_CODE_ERROR);
    }

    @ResponseBody
    @GetMapping("/graph")
    @ApiOperation(value = "验证图形获取")
    public Result<CaptchaResponse> captchaGraph() {
        String uuid = UUID.randomUUID().toString();
        String captcha = VerificationCodeUtil.generateVerificationCode(4, null);
        captchaComponent.saveCaptcha(uuid, captcha);
        CaptchaResponse captchaResponse = new CaptchaResponse();
        captchaResponse.setTtl(CAPTCHA_CACHE_TTL);
        captchaResponse.setGraphId(uuid);
        captchaResponse.setGraphUrl("/oauth/captcha/graph/print?graphId=" + uuid);

        return Result.ok(captchaResponse);

    }

    @ResponseBody
    @GetMapping("/validated-graph")
    @ApiOperation(value = "校验图形验证码")
    public Result<Boolean> validatedGraph(@ModelAttribute @Validated ValidatedGraphRequest validatedGraphRequest) {
        String captcha = captchaComponent.getCaptcha(validatedGraphRequest.getGraphId());
        if(StringUtils.isEmpty(captcha)){
            return Result.error(OauthErrorCodeEnum.CAPTCHA_CODE_ERROR);
        }
        String s = null;
        try {
            s = MD5Util.computeMD5(captcha.toUpperCase());
        } catch (NoSuchAlgorithmException e) {
            log.error("校验图形验证码失败, md5 计算异常", e);
            AssertUtil.error("校验图形验证码失败(md5计算异常), 请稍后重试!");
        }
        if(s != null && s.equals(validatedGraphRequest.getGraphMd5())){
            return Result.ok(Boolean.TRUE);
        }
        return Result.ok(Boolean.FALSE);
    }

    @GetMapping("/graph/print")
    @ApiOperation(value = "验证图形展示")
    public void captchaGraphPrint(HttpServletResponse response, @ModelAttribute @Validated CaptchaViewRequest captchaViewRequest) throws IOException {
        String captcha = captchaComponent.getCaptcha(captchaViewRequest.getGraphId());
        if (StringUtils.isBlank(captcha)) {
            captcha = "0000";
        }
        response.setContentType("image/png");
        response.setHeader("Cache-Control", "no-cache, no-store");
        response.setHeader("Pragma", "no-cache");
        long time = System.currentTimeMillis();
        response.setDateHeader("Last-Modified", time);
        response.setDateHeader("Date", time);
        response.setDateHeader("Expires", time);
        ServletOutputStream stream = response.getOutputStream();
        VerificationCodeUtil.outputImage(captchaViewRequest.getWidth(), captchaViewRequest.getHeight(), stream, captcha);
        stream.flush();
        stream.close();

    }

    @ResponseBody
    @GetMapping("/graph/base64")
    @ApiOperation(value = "验证图形base64展示")
    public Result<CaptchaResponse> captchaGraphBase64(@ModelAttribute @Validated CaptchaViewRequest captchaViewRequest) throws IOException {
        String captcha = captchaComponent.getCaptcha(captchaViewRequest.getGraphId());
        if (captcha != null) {
            String base64EncodedGraph = VerificationCodeUtil.outputImage(captchaViewRequest.getWidth(), captchaViewRequest.getHeight(), captcha);
            CaptchaResponse captchaResponse = new CaptchaResponse();
            captchaResponse.setBase64EncodedGraph(base64EncodedGraph);
            captchaResponse.setCaptcha(captcha);
            return Result.ok(captchaResponse);
        }
        return Result.error(OauthErrorCodeEnum.CAPTCHA_CODE_ERROR);
    }
}
